﻿/// <reference path="_namespace.js" />

/*****************************************************************************
Ajax library class definition. Kevin Robinson 2008.
Class: ajax.xna.RayCaster
/*****************************************************************************/

$addNamespace("ajax.xna");

$imports("ajax.drawing.Graphics");
$imports("ajax.drawing.GraphicsCanvas");
$imports("ajax.xna.RayCasterMap");
$imports("ajax.drawing.Point");
$imports("ajax.geometry.shapes.Rectangle");
$imports("ajax.xna.RayCasterLookups");
$imports("ajax.math.Ray");
$imports("ajax.math.Matrix");

worldToMapMatrix = ajax.math.Matrix.identity();
//-----------------------------------------------------------------------------
ajax.xna.RayCaster = function(game)
{   ///<field name="_player" type="ajax.xna.RayCasterPlayer"/>
    ajax.xna.RayCaster.superConstructor.call(this, game);    
    this._initialize();       
}
$extend("ajax.xna.RayCaster", "ajax.xna.DrawableGameComponent");
if ($getDesignMode())
    ajax.xna.RayCaster.prototype = ajax.xna.DrawableGameComponent.prototype;
//-----------------------------------------------------------------------------

// Public members
//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype._player    = null;                                 // the player (and camera)
ajax.xna.RayCaster.prototype.graphics   = ajax.drawing.Graphics.prototype;      // Our internal, native drawing surface
ajax.xna.RayCaster.prototype.tGraphics  = ajax.drawing.Graphics.prototype;      // Out internal Texturing graphics
ajax.xna.RayCaster.prototype.graphicsSpare = ajax.drawing.GraphicsCanvas.prototype;
ajax.xna.RayCaster.prototype.mapGraphics = ajax.drawing.Graphics.prototype;     // Our internal, native map drawing
ajax.xna.RayCaster.prototype._size       = ajax.geometry.shapes.Rectangle.prototype;
ajax.xna.RayCaster.prototype._scaledSize = ajax.geometry.shapes.Rectangle.prototype;
ajax.xna.RayCaster.prototype._halfSize   = ajax.geometry.shapes.Rectangle.prototype;
ajax.xna.RayCaster.prototype._zBuffer   = [];                                   // Our 1 dimensional zBuffer
ajax.xna.RayCaster.prototype._scaler    = 8;                                    // The amount we use to scale up our drawing
ajax.xna.RayCaster.prototype.worldMap   = ajax.xna.RayCasterMap.prototype;      // Will hold our map data. Used by Player.
ajax.xna.RayCaster.prototype.mapPosition = ajax.drawing.Point.prototype;
ajax.xna.RayCaster.prototype.lookups    = ajax.xna.RayCasterLookups.prototype;
ajax.xna.RayCaster.prototype.textures   = null;

ajax.xna.RayCaster.prototype.texturesShaded = null;
ajax.xna.RayCaster.prototype.flatShaded = false;
ajax.xna.RayCaster.prototype.texWidth   = 64;
ajax.xna.RayCaster.prototype.texHeight  = 64;
    
// Methods
//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.drawVerticalLine = function(x, drawStartY, drawEndY, color)
{///<summary>Uses this object's native HTML graphics to draw a vertical line</summary>
    // Scale up the graphics
    
    x           *= this._scaler;
    drawStartY  *= this._scaler;
    drawEndY    *= this._scaler;
    
    this.graphics.setColor(color);
    this.graphics.fillRect(x, drawStartY, Math.max(this._scaler, 1), drawEndY - drawStartY);        
}

ajax.xna.RayCaster.prototype.drawVerticalImage = function(x, drawStart, drawEnd, texNum, texX, textureSet, lineHeight)
{    
    var d = drawStart * 256 - this._scaledSize.height * 128 + lineHeight * 128;  //256 and 128 factors to avoid floats
    var texYStart = ((d * this.texHeight) / lineHeight) / 256;
    d = drawEnd * 256 - this._scaledSize.height * 128 + lineHeight * 128;
    var texYEnd   = ((d * this.texHeight) / lineHeight) / 256;            
    
    
    x           *= this._scaler;
    drawStart   *= this._scaler;
    drawEnd     *= this._scaler;
    
    //g.setColor(color);
    //g.fillRect(x, drawStart, Math.max(scaler-1, 1), drawEnd-drawStart);   
//    g.drawSlicedImage(textures, (texNum * texWidth) + texX, texStart, 1, texEnd, x, drawStart, Math.max(scaler-1, 1), drawEnd - drawStart);    
    texYStart = parseInt(texYStart);
    texYEnd   = parseInt(texYEnd);   

    try
    {
        this.tGraphics.drawImageFromRect(textureSet, texNum * this.texWidth + texX, texYStart, 1, texYEnd-texYStart, x, drawStart, Math.max(this._scaler, 1), drawEnd - drawStart);
    } catch (ex)
    {
        debugger;
    }
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.spriteSort = function(a, b)
{
    if (a.distance > b.distance)
        return -1;
    return 1;
}
        
//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.drawSprite = function(sprite, textures)
{            
    sprite = ajax.xna.SimpleSprite.cast(sprite);
    this._player = ajax.xna.RayCasterPlayer.cast(this._player);
    
    //translate sprite position to relative to camera
    var spriteX = sprite.position.x - this._player.position.x;// sprite.x - posX;
    var spriteY = sprite.position.y - this._player.position.y;// posY;
     
    //transform sprite with the inverse camera matrix
    // [ planeX   dirX ] -1                                       [ dirY      -dirX ]
    // [               ]       =  1/(planeX*dirY-dirX*planeY) *   [                 ]
    // [ planeY   dirY ]                                          [ -planeY  planeX ]
  
    var invDet = 1.0 / (this._player.plane.x * this._player.direction.y - this._player.direction.x * this._player.plane.y);
    //var invDet = 1.0 / (planeX * dirY - dirX * planeY); //required for correct matrix multiplication
  
    //var transformX = invDet * (dirY * spriteX - dirX * spriteY);
    //var transformY = invDet * (-planeY * spriteX + planeX * spriteY); //this is actually the depth inside the screen, that what Z is in 3D       
    var transformX = invDet * (this._player.direction.y * spriteX - this._player.direction.x * spriteY);            
    var transformY = invDet * (-this._player.plane.y * spriteX + this._player.plane.x * spriteY);    //this is actually the depth inside the screen, that what Z is in 3D 
            
    var spriteScreenX = parseInt( this._halfSize.width * (1 + transformX / transformY));        
  
    //calculate height of the sprite on screen
    var spriteHeight = Math.abs(parseInt(this._scaledSize.height / (transformY))); //using "transformY" instead of the real distance prevents fisheye
    //calculate lowest and highest pixel to fill in current stripe
    var drawStartY = -spriteHeight / 2 + this._halfSize.height;
    if(drawStartY < 0) 
        drawStartY = 0;
    var drawEndY = spriteHeight / 2 + this._halfSize.height;
    if(drawEndY >= this._scaledSize.height) 
        drawEndY = this._scaledSize.height; // - 1;
  
    //calculate width of the sprite
    var spriteWidth = Math.abs( parseInt (this._scaledSize.height / (transformY)));
    var drawStartX = -spriteWidth / 2 + spriteScreenX;            
    if(drawStartX < 0)                                           
        drawStartX = 0;
    
    var drawEndX = spriteWidth / 2 + spriteScreenX;            
    if(drawEndX >= this._scaledSize.width)             
        drawEndX = this._scaledSize.width - 1;                        
        
    // Faster sprite rendering.            
    var spriteTexXStart = 0; var spriteTexXEnd = 0;
    var foundFirst = false; var foundLast = false;
    var firstStripe = 0; var lastStripe = 0;
    for (var stripe = parseInt(drawStartX); stripe < parseInt(drawEndX)+1; stripe++)
    {                        
        
        //the conditions in the if are:
        //1) it's in front of camera plane so you don't see things behind you
        //2) it's on the screen (left)
        //3) it's on the screen (right)
        //4) ZBuffer, with perpendicular distance                
        if (transformY > 0 && stripe >= 0 && stripe < this._scaledSize.width && transformY < this._zBuffer[stripe])
        {
            var spriteTexX = parseInt(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * this.texWidth / spriteWidth) / 256;
            
            if (!foundFirst)
            {
                firstStripe = stripe;
                spriteTexXStart = spriteTexX;
                foundFirst = true;
            }
            else
            {
                lastStripe = stripe;
                spriteTexXEnd = spriteTexX;
                foundLast = true;
            }                                            
        }
    }
    if (!foundLast)
    {
        foundLast = foundFirst;
        spriteTexXEnd = spriteTexXStart;
        lastStripe = firstStripe;
    }
    
    if (foundFirst && foundLast)
    {        
        spriteTexXStart = Math.max(Math.round(spriteTexXStart), 1);
        spriteTexXEnd   = Math.max(Math.round(spriteTexXEnd), 1);
        
        
        var d = 0;
        d = drawStartY * 256 - this._scaledSize.height * 128 + spriteHeight * 128;  //256 and 128 factors to avoid floats
        var texYStart = ((d * this.texHeight) / spriteHeight) / 256;
        d = drawEndY * 256 - this._scaledSize.height * 128 + spriteHeight * 128;
        var texYEnd   = ((d * this.texHeight) / spriteHeight) / 256;                 
        
        
        lastStripe  += 1; //(inclusive)
        
        // Scale it up.
        firstStripe *= this._scaler;        
        lastStripe  *= this._scaler;       
        drawStartY  *= this._scaler;
        drawEndY    *= this._scaler;                
        
        
        this.tGraphics.drawImageFromRect(textures, 
            sprite.texNum * this.texWidth + spriteTexXStart, texYStart, spriteTexXEnd - spriteTexXStart, texYEnd - texYStart,
            firstStripe, drawStartY, lastStripe - firstStripe, drawEndY - drawStartY
        ); 
        //drawSprite(firstStripe, lastStripe, spriteTexXStart, spriteTexXEnd, drawStartY, drawEndY, sprite.texture, textures, size, spriteHeight);        
    }
    
    /*
    // Proper sprite rendering (slow)
    // loop through every vertical stripe of the sprite on screen            
    for (var stripe = drawStartX; stripe < drawEndX; stripe++)
    {
        var spriteTexX = parseInt(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) / 256;
        //the conditions in the if are:
        //1) it's in front of camera plane so you don't see things behind you
        //2) it's on the screen (left)
        //3) it's on the screen (right)
        //4) ZBuffer, with perpendicular distance
        if (transformY > 0 && stripe > 0 && stripe < size.width && transformY < ZBuffer[stripe])
        {
            // Draw it     
            verImage(stripe, drawStartY, drawEndY, sprite.texture, spriteTexX, textures, size.height, spriteHeight, 1);                    
        }
    }
    */

}


// Public Methods
//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.getPlayer = function()
{///<returns type="ajax.xna.RayCasterPlayer"/>
    return this._player;    
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype._initialize = function()
{
    // Create a player
    this._player = $new("ajax.xna.RayCasterPlayer", this); 
    this.textures = this.getDocument().createElement("img");
    this.textures.src = ajax.domain + "images/wolftextures2.png"; 
    this.texturesShaded = this.getDocument().createElement("img");
    this.texturesShaded.src = ajax.domain + "images/wolftexturesShaded.png";
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.drawMap = function()
{   
    
    this.mapGraphics.clear(this.getGame().backColour);
    
    var position = new ajax.math.Vector3();    
    for (var x = 0; x < this.worldMap.blocks.length; x++)
    {
        for (var y = 0; y < this.worldMap.blocks[x].length; y++)
        {        
            var colourIndex = this.worldMap.blocks[x][y];
            if (colourIndex != 0)
            {
                position.x = x; position.y = this.worldMap.blocks[0].length - y;
                position.transformCoordinate(worldToMapMatrix);                
                this.mapGraphics.setColor(this.worldMap.colours[colourIndex-1]);
                //this.mapGraphics.fillRect(x*5, (this.worldMap.blocks[x].length -  y) * 5, 5, 5);
                this.mapGraphics.fillRect(position.x, position.y, 2, 2);
            }
        }
    }
    this.mapGraphics.repaint();
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.getSize = function()
{///<returns type="ajax.geometry.shapes.Rectangle"/>
    return this._size;
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.setSize = function(size)
{
    this._size = size;    
    this._scaledSize = ajax.geometry.shapes.Rectangle.divideScalar(this._size, this._scaler);    
    this._halfSize = ajax.geometry.shapes.Rectangle.divideScalar(this._scaledSize, 2);
    
    // Configure lookups based on SCALED size
    this.lookups = new ajax.xna.RayCasterLookups(this._scaledSize);                       
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.calculateWallX = function(side, ray, mapPoint, step)
{
    ray = ajax.math.Ray.cast(ray);
    mapPoint = ajax.drawing.Point.cast(mapPoint);
    step = ajax.math.Vector3.cast(step);
    
    // Calculate value of wallX
    var wallX; // Where EXACTLY the wall was hit
    if (side == 1)
        wallX = ray.position.x + ( (mapPoint.y - ray.position.y + (1 - step.y) / 2) / ray.direction.y) * ray.direction.x;
    else
        wallX = ray.position.y + ( (mapPoint.x - ray.position.x + (1 - step.x) / 2) / ray.direction.x) * ray.direction.y;
    
    wallX -= Math.floor(wallX);
    
    return wallX;    
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.initialize = function()
{
    ajax.xna.RayCaster.superClass.initialize.call(this);
    
    // Set sizes
    // Set our size as per the graphics device our game is using
    this.setSize(this.getGame().graphicsDevice.getSize());
    
    
    // Get handles to current graphics & 3d device...
    var g3d = this.getGame().graphicsDevice;
    var g = g3d.graphics;
    
    // Create 3 layers to render to   
    var applyAttributes = function(ele)
    {
        ele.style.position = "absolute";
        ele.style.left = ele.style.top = "0px";
        ele.style.width = g3d.graphics.width + "px"; ele.style.height = g3d.graphics.height + "px";            
    } 
    
    var graphicsLayer       = this.getDocument().createElement("div"); applyAttributes(graphicsLayer); 
    var tGraphicsLayer      = this.getDocument().createElement("div"); applyAttributes(tGraphicsLayer); 
    var mapGraphicsLayer    = this.getDocument().createElement("div"); applyAttributes(mapGraphicsLayer);
    var graphicsSpareLayer = this.getDocument().createElement("div"); applyAttributes(graphicsSpareLayer);
    

    // Attach our graphics layers as siblings to the 3d graphics layer
    var parentLayer = g3d.getLayer().parentNode;
    
    var background = this.getDocument().createElement("img");
    background.src = ajax.domain + "images/RayBackground.png";
    background.style.position = "absolute";
    background.style.left = background.style.top = "0px";
    background.style.width = this.getSize().width + "px";
    background.style.height = this.getSize().height + "px";
    parentLayer.appendChild(background);
    
    parentLayer.appendChild(graphicsLayer);            
    parentLayer.appendChild(tGraphicsLayer);
    parentLayer.appendChild(mapGraphicsLayer);
    parentLayer.appendChild(graphicsSpareLayer);
    
    
    
    // Create our own native version and place them into their allocated layers.
    this.graphics = new ajax.drawing.Graphics(this.getDocument(), 
        graphicsLayer, g.width, g.height
    );
    this.tGraphics = new ajax.drawing.GraphicsCanvas(this.getDocument(),
        tGraphicsLayer, g.width, g.height
    );
    this.mapGraphics = new ajax.drawing.Graphics(this.getDocument(),
        mapGraphicsLayer, g.width, g.height
    );        
    this.graphicsSpare = new ajax.drawing.GraphicsCanvas(this.getDocument(),
        graphicsSpareLayer, g.width, g.height
    );
    
    // draw to the spare
    /*
    this.graphicsSpare.clear(new ajax.drawing.Colour(255, 0, 0));
    this.graphicsSpare.drawImage(this.textures, 0, 0);
    this.graphicsSpare.repaint();
    */
    
    
    this.zBuffer = [];
    this.worldMap = new ajax.xna.RayCasterMap(); 
    worldToMapMatrix = ajax.math.Matrix.identity(); // ajax.math.Matrix.translation(new ajax.math.Vector3(0, this.worldMap.blocks[0].length, 0));
    worldToMapMatrix.multiplyReversed(ajax.math.Matrix.scaling(new ajax.math.Vector3(5, 5, 0)));        
    this.drawMap();              
    
    //var scroller = $new("ajax.effects.Scroll", this.getGame().getContent());
    //scroller.scroll();
}


//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.update = function(gameTime)
{     
    // Update our player.   
   ajax.xna.RayCasterPlayer.cast(this._player).update(gameTime);   
}

//-----------------------------------------------------------------------------
ajax.xna.RayCaster.prototype.draw = function(gameTime)
{    
    gameTime = ajax.drawing.Timer.cast(gameTime);
    //TODO: Add your draw code here 
    var player = ajax.xna.RayCasterPlayer.cast(this._player);
    
    
    this.graphics.clear(this.getGame().backColour);      
    this.tGraphics.clear(this.getGame().backColour);
    this.graphicsSpare.clear(this.getGame().backColour);
    
    // Start drawing the rays
    var map = this.graphicsSpare.getContext();
    map.beginPath();
    map.fillStyle = "#3366cc";    
    var mapPlayerPos = ajax.math.Vector3.createFrom(player.position);              
    mapPlayerPos.y = this.worldMap.blocks[0].length - mapPlayerPos.y +1;
    //mapPlayerPos.transformCoordinate(worldToMapMatrix);    
    mapPlayerPos.multiplyScalar(5);
     
     
    map.arc(mapPlayerPos.x, mapPlayerPos.y, 2, 0, 2*Math.PI, true); // Draw circle for player
    map.fill();
    map.beginPath();
    map.moveTo(mapPlayerPos.x, mapPlayerPos.y);
    
    
    // TODO: have a method that does this loop and fills a bunch of arrays with the data we need
    // Then we might be able to do optimizations, like, when drawing flat shaded walls
    // instead of drawing a rectangle for each strip, we could use a wall section wall[x] to wall[x+4]
    // and draw a polygon instead (giving a speed of low res but a look of high res). Like this:
    /*
        tl=[wall[i]*2, 150-wallH1*h];
		tr=[wall[i+2]*2, 150-wallH2*h]
		br=[wall[i+2]*2, tr[1]+wallH2*2];
		bl=[wall[i]*2, tl[1]+wallH1*2]
		...
		canvas.beginPath();
		canvas.moveTo(tl[0], tl[1]);
		canvas.lineTo(tr[0], tr[1]);
		canvas.lineTo(br[0], br[1]);
		canvas.lineTo(bl[0], bl[1]);
		canvas.fillStyle = linGrad;
		canvas.fill();
    */
        
    for (var x = 0; x < this._scaledSize.width; x++)
    {        
        
        // -1 to 1 X value
        var cameraX = this.lookups.screenScanX[x];     
        
        
        // Ray starts with player position & direction (centre of the screen)   
        var ray = ajax.math.Ray.cast(this.lookups.rays[x]);   
        ray.position.copyValuesFrom(player.position);
        ray.direction.copyValuesFrom(player.direction);
                                                              
        // alter this ray direction to correct offset from center.
        var rayOffset = ajax.math.Vector3.cast(this.lookups.rayOffsets[x]);
        rayOffset.copyValuesFrom(player.plane);
        rayOffset.multiplyScalar(cameraX);                             
        ray.direction.add( rayOffset );        
        
        
        
        // Which box of map we're in                
        var mapPoint = ajax.drawing.Point.cast(this.lookups.mapPoints[x]);
        mapPoint.x   = parseInt(ray.position.x);
        mapPoint.y   = parseInt(ray.position.y);

        
        // Length of ray from current position to next x or y-side
        var sideDistance = ajax.math.Vector3.cast(this.lookups.sideDistances[x]);
        
        // Length of ray from one x or y-side to next x or y-side
        var deltaDistance = ajax.math.Vector3.cast(this.lookups.deltaDistances[x]);                
        deltaDistance.x = Math.sqrt( 1 + (ray.direction.y * ray.direction.y) / (ray.direction.x * ray.direction.x) );
        deltaDistance.y = Math.sqrt( 1 + (ray.direction.x * ray.direction.x) / (ray.direction.y * ray.direction.y) );
        
        var perpWallDist = this.lookups.perpWallDistances[x];
        
        // What direction to step in x or y-direction (either +1 or -1)
        var step = ajax.math.Vector3.cast(this.lookups.steps[x]);
        
        var hit = false;    // was there a wall hit?
        var side = 0;           // was a NS or EW wall hit??
        
        
        // Calculate step and initial sideDist
        if (ray.direction.x < 0)
        {
            step.x = -1;
            sideDistance.x = (ray.position.x - mapPoint.x) * deltaDistance.x;
        }
        else
        {
            step.x = 1;
            sideDistance.x = (mapPoint.x + 1 - ray.position.x) * deltaDistance.x;
        }
        
        if (ray.direction.y < 0)
        {
            step.y = -1;
            sideDistance.y = (ray.position.y - mapPoint.y) * deltaDistance.y;
        }
        else
        {
            step.y = 1;
            sideDistance.y = (mapPoint.y + 1 - ray.position.y) * deltaDistance.y;
        }
        
        
         // Perform DDA
         while (!hit)
         {
            // Jump to next map square, OR in x-direction, OR in y-direction
            if (sideDistance.x < sideDistance.y)
            {
                sideDistance.x += deltaDistance.x;
                mapPoint.x += step.x;
                side = 0;
            }
            else
            {
                sideDistance.y += deltaDistance.y;
                mapPoint.y += step.y;
                side = 1;
            }
            
            // Check if ray has hit a wall
            if (this.worldMap.blocks[mapPoint.x][mapPoint.y] > 0)
                hit = true;
         }        
         
         if (side == 0)
            perpWallDist = Math.abs( (mapPoint.x - ray.position.x + (1 - step.x) / 2) / ray.direction.x );
         else
            perpWallDist = Math.abs( (mapPoint.y - ray.position.y + (1 - step.y) / 2) / ray.direction.y );
         
         
         // Set the z buffer for the SPRITE casting
         this._zBuffer[x] = perpWallDist;                 
         
         
         
         // Calculate height to draw on screen
         var lineHeight = Math.abs(parseInt(this._scaledSize.height / perpWallDist) );
         
         // calculate lowest and heighest pixel to fill the current stripe            
         var drawStart = -lineHeight / 2 + this._halfSize.height;            
         if (drawStart < 0)
             drawStart = 0;
         var drawEnd = lineHeight / 2 + this._halfSize.height;            
         if (drawEnd >= this._scaledSize.height)
             drawEnd = this._scaledSize.height;// - 1;
             
         var mapTileValue = this.worldMap.blocks[mapPoint.x][mapPoint.y]-1;
         
         if (this.flatShaded)
         {
             var mapColour = this.worldMap.colours[mapTileValue];
             var colorRgb = new ajax.drawing.Colour(mapColour.r, mapColour.g, mapColour.b);            
                    
             // Give x and y sides different brightness
             if (side == 1)
                 colorRgb.setValues(colorRgb.r/2, colorRgb.g/2, colorRgb.b/2, colorRgb.a);
                               
             colorRgb.multiplyScalar(ajax.drawing.Colour.calculateFogging(0.1, perpWallDist));         
             
             this.drawVerticalLine(x, drawStart, drawEnd, colorRgb);    
         }
         else
         {
            // Texturing Calculations
                var texNum = mapTileValue -1; // 1 subtracted so texture 0 can be used
            var texNum = mapTileValue; // 1 subtracted so texture 0 can be used
            
            // Calculate value of wallX
            var wallX = this.calculateWallX(side, ray, mapPoint, step);
            
            // x coordinate on the texture
            var texX = parseInt(wallX * this.texWidth);
            if (side == 0 && ray.direction.x > 0)
                texX = this.texWidth - texX - 1;
            if (side == 1 && ray.direction.y < 0)
                texX = this.texWidth - texX - 1;
                
            var textureSet = (side == 1) ? this.texturesShaded : this.textures; 
            
            // test rendering from a canvas
            //if (ajax.Browser.isFirefox)
            //    textureSet = this.graphicsSpare.canvas;
                 
            this.drawVerticalImage(x, drawStart, drawEnd, texNum, texX, textureSet, lineHeight);
                      
            //verImage(x, drawStart, drawEnd, texNum, texX, textureSet, size.height, lineHeight);
         }
         
         
        
        // Draw ray onto the map to check it...                
        mapPlayerPos.x = player.position.x + ray.direction.x * perpWallDist; 
        mapPlayerPos.y = this.worldMap.blocks[0].length - player.position.y + 1 - ray.direction.y * perpWallDist;
        mapPlayerPos.transformCoordinate(worldToMapMatrix);                
        map.lineTo(mapPlayerPos.x, mapPlayerPos.y);                    
         
    } // End each stripe
    
    map.fillStyle="#FF0000"
	map.fill();


	/*
	
	// SPRITE CASTING 
	// sort sprites from far to close
	var sprite;
	// Set each sprite's distance.
	for (var i = 0; i < this.worldMap.sprites.length; i++)
	{
	sprite = ajax.xna.SimpleSprite.cast(this.worldMap.sprites[i]);
	var v = ajax.math.Vector3.subtract(player.position, sprite.position);         
	sprite.distance = v.lengthSq(); //sqrt not taken, unneeded        
	}
    
	this.worldMap.sprites.sort(this.spriteSort);

	// After sorting the sprites, do the projection and draw them
	for (var i = 0; i < this.worldMap.sprites.length; i++)        
	{                                                                           
	var sprite = this.worldMap.sprites[i];                   
	this.drawSprite(sprite, this.textures); 
                                             
	} // Each sprite
	*/
    //this.graphics.setColor($new("ajax.drawing.Colour", 255, 0, 0));
    //this.graphics.fillRect(player.position.x * 5, (this.worldMap.blocks[0].length - player.position.y) * 5 + 4, 4, 4);
    
    this.graphics.repaint();    
    this.tGraphics.repaint();
    this.graphicsSpare.repaint();
    
    
}


// Statics
//-----------------------------------------------------------------------------
ajax.xna.RayCaster.cast = function(obj)
{///<returns type="ajax.xna.RayCaster"/>
    return obj;
}
